package com.penghaonan.appframework.utils

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.res.Resources
import android.content.res.TypedArray
import android.graphics.Color
import android.graphics.Outline
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.os.Build
import android.text.method.LinkMovementMethod
import android.util.DisplayMetrics
import android.util.TypedValue
import android.view.Display
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.ViewOutlineProvider
import android.view.Window
import android.view.WindowManager
import android.widget.EditText
import android.widget.TextView
import androidx.annotation.RequiresApi
import androidx.core.graphics.ColorUtils
import androidx.core.text.HtmlCompat
import com.penghaonan.appframework.AppDelegate
import com.penghaonan.appframework.utils.Logger.Companion.i
import xyz.penghaonan.framework.R
import kotlin.math.pow
import kotlin.math.roundToInt
import kotlin.math.sqrt

/**
 * Created by carl on 9/16/15.
 */
object UIUtils {
    @JvmStatic
    fun dip2Px(dpValue: Float): Int {
        val scale: Float = AppDelegate.getApp().resources.displayMetrics.density
        return (dpValue * scale + 0.5f).toInt()
    }

    fun px2Dip(pxValue: Float): Int {
        val scale: Float = AppDelegate.getApp().resources.displayMetrics.density
        return (pxValue / scale + 0.5f).toInt()
    }

    private val windowMetrics: DisplayMetrics
        get() {
            val metric: DisplayMetrics = DisplayMetrics()
            val wm: WindowManager = AppDelegate.getApp()
                .getSystemService(Context.WINDOW_SERVICE) as WindowManager
            wm.defaultDisplay.getMetrics(metric)
            return metric
        }

    private val screenMetrics: DisplayMetrics
        get() {
            val metric: DisplayMetrics = DisplayMetrics()
            val wm: WindowManager = AppDelegate.getApp()
                .getSystemService(Context.WINDOW_SERVICE) as WindowManager
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                wm.defaultDisplay.getRealMetrics(metric)
            } else {
                wm.defaultDisplay.getMetrics(metric)
            }
            return metric
        }

    val windowWidth: Int
        get() = windowMetrics.widthPixels

    val windowHeight: Int
        get() = windowMetrics.heightPixels

    val screenWidth: Int
        get() = screenMetrics.widthPixels

    val screenHeight: Int
        get() = screenMetrics.heightPixels

    @JvmStatic
    val statusBarHeight: Int
        get() {
            var result: Int = 0
            val resourceId: Int = AppDelegate.getApp().resources
                .getIdentifier("status_bar_height", "dimen", "android")
            if (resourceId > 0) {
                result = AppDelegate.getApp().resources.getDimensionPixelOffset(resourceId)
            }

            return result
        }

    val navigationBarHeight: Int
        get() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                if (!hasSoftKeys(
                        AppDelegate.getApp()
                            .getSystemService(Context.WINDOW_SERVICE) as WindowManager
                    )
                ) {
                    return 0
                }
            }
            val resources: Resources = AppDelegate.getApp().resources
            val resourceId: Int =
                resources.getIdentifier("navigation_bar_height", "dimen", "android")
            return resources.getDimensionPixelSize(resourceId)
        }

    fun setLightStatusBar(activity: Activity?, dark: Boolean) {
        if (activity == null) {
            return
        }
        val decor: View = activity.window.decorView
        if (dark) {
            val ui: Int = decor.systemUiVisibility
            decor.systemUiVisibility = ui or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
        } else {
            var ui: Int = decor.systemUiVisibility
            ui = ui and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
            decor.systemUiVisibility = ui
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
    private fun hasSoftKeys(windowManager: WindowManager): Boolean {
        val d: Display = windowManager.defaultDisplay

        val realDisplayMetrics: DisplayMetrics = DisplayMetrics()
        d.getRealMetrics(realDisplayMetrics)

        val realHeight: Int = realDisplayMetrics.heightPixels
        val realWidth: Int = realDisplayMetrics.widthPixels

        val displayMetrics: DisplayMetrics = DisplayMetrics()
        d.getMetrics(displayMetrics)

        val displayHeight: Int = displayMetrics.heightPixels
        val displayWidth: Int = displayMetrics.widthPixels

        return (realWidth - displayWidth) > 0 || (realHeight - displayHeight) > 0
    }

    /**
     * 设置StatusBar颜色
     */
    fun initActivityStatusNavigationBarColor(activity: Activity?, color: Int) {
        initActivityStatusNavigationBarColor(activity, color, 0)
    }

    /**
     * 设置StatusBar， NavigationBar颜色
     */
    @JvmStatic
    fun initActivityStatusNavigationBarColor(activity: Activity?, statusColor: Int, navigationColor: Int) {
        if (activity != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            val window: Window = activity.window
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
            if (statusColor != 0) {
                window.statusBarColor = statusColor
            }
            if (navigationColor != 0) {
                window.navigationBarColor = navigationColor
            }
        }
    }

    /**
     * 点击态，透明度
     * 列表中无效
     */
    @SuppressLint("ClickableViewAccessibility")
    fun changeAlpha(view: View?, alpha: Float) {
        view?.setOnTouchListener { v, event ->
            val action: Int = event.action
            i("action:$action")
            when (action) {
                MotionEvent.ACTION_DOWN -> v.alpha = alpha
                MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_OUTSIDE, MotionEvent.ACTION_UP -> v.alpha =
                    1f
            }
            false
        }
    }

    val wrapLayoutParams: ViewGroup.LayoutParams
        get() = ViewGroup.LayoutParams(
            ViewGroup.LayoutParams.WRAP_CONTENT,
            ViewGroup.LayoutParams.WRAP_CONTENT
        )

    val matchLayoutParams: ViewGroup.LayoutParams
        get() {
            return ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
            )
        }

    @JvmStatic
    val matchWrapLayoutParams: ViewGroup.LayoutParams
        get() {
            return ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
            )
        }

    @JvmStatic
    fun setHtmlText(textView: TextView?, html: String?) {
        if (textView == null || html == null) {
            return
        }
        textView.text = HtmlCompat.fromHtml(
            html,
            HtmlCompat.FROM_HTML_MODE_LEGACY
        )
        textView.movementMethod = LinkMovementMethod.getInstance()
    }

    fun setHintText(editText: EditText?, html: String?) {
        if (editText == null || html == null) {
            return
        }
        editText.hint = HtmlCompat.fromHtml(
            html,
            HtmlCompat.FROM_HTML_MODE_LEGACY
        )
        editText.movementMethod = LinkMovementMethod.getInstance()
    }

    fun createViewBackgroundGuideAnim(
        view: View?,
        startColor: Int,
        endColor: Int,
        cycleCount: Int,
        duration: Long
    ): ValueAnimator? {
        if (view == null) {
            return null
        }
        try {
            val `object`: Any = view.getTag(R.id.framework_guide_anim)
            if (`object` is ValueAnimator) {
                `object`.cancel()
                view.setTag(R.id.framework_guide_anim, null)
                view.setTag(R.id.framework_guide_anim_count, null)
            }
        } catch (e: Exception) {
            Logger.e(e)
        }
        val valueAnimator: ValueAnimator = ValueAnimator.ofFloat(0f, 1f)
        valueAnimator.addUpdateListener { animator ->
            val progress: Float = animator.animatedValue as Float
            val color: Int = if (progress < 0.5f) {
                ColorUtils.blendARGB(startColor, endColor, progress)
            } else {
                ColorUtils.blendARGB(startColor, endColor, 1 - progress)
            }
            view.setBackgroundColor(color)
        }
        valueAnimator.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator) {
                super.onAnimationEnd(animation)
                val `object`: Any? = view.getTag(R.id.framework_guide_anim_count)
                var count: Int = 0
                if (`object` != null) {
                    try {
                        count = `object` as Int
                    } catch (ignore: Exception) {
                    }
                }
                count++
                if (count < cycleCount) {
                    view.setTag(R.id.framework_guide_anim_count, count)
                    valueAnimator.start()
                } else {
                    view.setTag(R.id.framework_guide_anim, null)
                    view.setTag(R.id.framework_guide_anim_count, null)
                }
            }
        })
        valueAnimator.setDuration(duration)
        view.setTag(R.id.framework_guide_anim, valueAnimator)
        return valueAnimator
    }

    @JvmStatic
    val clickableItemBackgroundDrawable: Drawable?
        get() {
            val typedValue: TypedValue = TypedValue()
            AppDelegate.getApp().theme
                .resolveAttribute(android.R.attr.selectableItemBackground, typedValue, true)
            val attribute: IntArray =
                intArrayOf(android.R.attr.selectableItemBackground)
            val typedArray: TypedArray = AppDelegate.getApp().theme
                .obtainStyledAttributes(typedValue.resourceId, attribute)
            val drawable: Drawable? = typedArray.getDrawable(0)
            typedArray.recycle()
            return drawable
        }

    fun setViewRadius(view: View, radius: Int) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            view.clipToOutline = true
            view.outlineProvider = object : ViewOutlineProvider() {
                override fun getOutline(
                    view: View,
                    outline: Outline
                ) {
                    outline.setRoundRect(
                        0,
                        0,
                        view.measuredWidth,
                        view.measuredHeight,
                        radius.toFloat()
                    )
                }
            }
        }
    }

    fun changeAlpha(alpha: Float, color: Int): Int {
        return ((alpha * 255).toInt() shl 6 * 4) or (color and 0x00FFFFFF)
    }

    fun changeAlpha(alpha: Int, color: Int): Int {
        return (alpha shl 6 * 4) or (color and 0x00FFFFFF)
    }

    fun addAlpha(alpha: Float, color: Int): Int {
        val originAlpha: Int = Color.alpha(color)
        return changeAlpha((originAlpha * alpha).toInt(), color)
    }


    fun progressValue(from: Float, to: Float, progress: Float): Float {
        return (to - from) * progress + from
    }

    fun distanceBetween(x1: Int, y1: Int, x2: Int, y2: Int): Int {
        return sqrt(
            (x1 - x2).toDouble().pow(2.0) + ((y1 - y2).toDouble()).pow(2.0)
        ).roundToInt()
    }
}

fun View.contains(x: Int, y: Int): Boolean {
    val rect = Rect()
    if(!this.getGlobalVisibleRect(rect)) {
        return false
    }
    return rect.contains(x, y)
}

fun View.contains(x: Float, y: Float): Boolean {
    val rect = Rect()
    if(!this.getGlobalVisibleRect(rect)) {
        return false
    }
    return rect.contains(x.toInt(), y.toInt())
}
